home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 45975 / 45975.xpi / modules / ext / Observers.js
Text File  |  2009-11-19  |  7KB  |  184 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Observers.
  15.  *
  16.  * The Initial Developer of the Original Code is Daniel Aquino.
  17.  * Portions created by the Initial Developer are Copyright (C) 2008
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Daniel Aquino <mr.danielaquino@gmail.com>
  22.  *   Myk Melez <myk@mozilla.org>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. let EXPORTED_SYMBOLS = ["Observers"];
  39.  
  40. const Cc = Components.classes;
  41. const Ci = Components.interfaces;
  42. const Cr = Components.results;
  43. const Cu = Components.utils;
  44.  
  45. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  46.  
  47. /**
  48.  * A service for adding, removing and notifying observers of notifications.
  49.  * Wraps the nsIObserverService interface.
  50.  *
  51.  * @version 0.2
  52.  */
  53. let Observers = {
  54.   /**
  55.    * Register the given callback as an observer of the given topic.
  56.    *
  57.    * @param   topic       {String}
  58.    *          the topic to observe
  59.    *
  60.    * @param   callback    {Object}
  61.    *          the callback; an Object that implements nsIObserver or a Function
  62.    *          that gets called when the notification occurs
  63.    *
  64.    * @param   thisObject  {Object}  [optional]
  65.    *          the object to use as |this| when calling a Function callback
  66.    *
  67.    * @returns the observer
  68.    */
  69.   add: function(topic, callback, thisObject) {
  70.     let observer = new Observer(topic, callback, thisObject);
  71.     this._cache.push(observer);
  72.     this._service.addObserver(observer, topic, true);
  73.  
  74.     return observer;
  75.   },
  76.  
  77.   /**
  78.    * Unregister the given callback as an observer of the given topic.
  79.    *
  80.    * @param topic       {String}
  81.    *        the topic being observed
  82.    *
  83.    * @param callback    {Object}
  84.    *        the callback doing the observing
  85.    *
  86.    * @param thisObject  {Object}  [optional]
  87.    *        the object being used as |this| when calling a Function callback
  88.    */
  89.   remove: function(topic, callback, thisObject) {
  90.     // This seems fairly inefficient, but I'm not sure how much better
  91.     // we can make it.  We could index by topic, but we can't index by callback
  92.     // or thisObject, as far as I know, since the keys to JavaScript hashes
  93.     // (a.k.a. objects) can apparently only be primitive values.
  94.     let [observer] = this._cache.filter(function(v) v.topic      == topic    &&
  95.                                                     v.callback   == callback &&
  96.                                                     v.thisObject == thisObject);
  97.     if (observer) {
  98.       this._service.removeObserver(observer, topic);
  99.       this._cache.splice(this._cache.indexOf(observer), 1);
  100.     }
  101.   },
  102.  
  103.   /**
  104.    * Notify observers about something.
  105.    *
  106.    * @param topic   {String}
  107.    *        the topic to notify observers about
  108.    *
  109.    * @param subject {Object}  [optional]
  110.    *        some information about the topic; can be any JS object or primitive
  111.    *
  112.    * @param data    {String}  [optional] [deprecated]
  113.    *        some more information about the topic; deprecated as the subject
  114.    *        is sufficient to pass all needed information to the JS observers
  115.    *        that this module targets; if you have multiple values to pass to
  116.    *        the observer, wrap them in an object and pass them via the subject
  117.    *        parameter (i.e.: { foo: 1, bar: "some string", baz: myObject })
  118.    */
  119.   notify: function(topic, subject, data) {
  120.     subject = (typeof subject == "undefined") ? null : new Subject(subject);
  121.        data = (typeof    data == "undefined") ? null : data;
  122.     this._service.notifyObservers(subject, topic, data);
  123.   },
  124.  
  125.   _service: Cc["@mozilla.org/observer-service;1"].
  126.             getService(Ci.nsIObserverService),
  127.  
  128.   /**
  129.    * A cache of observers that have been added.
  130.    *
  131.    * We use this to remove observers when a caller calls |remove|.
  132.    *
  133.    * XXX This might result in reference cycles, causing memory leaks,
  134.    * if we hold a reference to an observer that holds a reference to us.
  135.    * Could we fix that by making this an independent top-level object
  136.    * rather than a property of this object?
  137.    */
  138.   _cache: []
  139. };
  140.  
  141.  
  142. function Observer(topic, callback, thisObject) {
  143.   this.topic = topic;
  144.   this.callback = callback;
  145.   this.thisObject = thisObject;
  146. }
  147.  
  148. Observer.prototype = {
  149.   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
  150.   observe: function(subject, topic, data) {
  151.     // Extract the wrapped object for subjects that are one of our wrappers
  152.     // around a JS object.  This way we support both wrapped subjects created
  153.     // using this module and those that are real XPCOM components.
  154.     if (subject && typeof subject == "object" &&
  155.         ("wrappedJSObject" in subject) &&
  156.         ("observersModuleSubjectWrapper" in subject.wrappedJSObject))
  157.       subject = subject.wrappedJSObject.object;
  158.  
  159.     if (typeof this.callback == "function") {
  160.       if (this.thisObject)
  161.         this.callback.call(this.thisObject, subject, data);
  162.       else
  163.         this.callback(subject, data);
  164.     }
  165.     else // typeof this.callback == "object" (nsIObserver)
  166.       this.callback.observe(subject, topic, data);
  167.   }
  168. }
  169.  
  170.  
  171. function Subject(object) {
  172.   // Double-wrap the object and set a property identifying the wrappedJSObject
  173.   // as one of our wrappers to distinguish between subjects that are one of our
  174.   // wrappers (which we should unwrap when notifying our observers) and those
  175.   // that are real JS XPCOM components (which we should pass through unaltered).
  176.   this.wrappedJSObject = { observersModuleSubjectWrapper: true, object: object };
  177. }
  178.  
  179. Subject.prototype = {
  180.   QueryInterface: XPCOMUtils.generateQI([]),
  181.   getHelperForLanguage: function() {},
  182.   getInterfaces: function() {}
  183. };
  184.